package br.unifor.cct.mia.xover;

import java.util.List;

import br.unifor.cct.mia.dataenhancement.Attribute;
import br.unifor.cct.mia.dataenhancement.Structure;
import br.unifor.cct.mia.evolutionary.FeatureConstructionGenotype;
import br.unifor.cct.mia.evolutionary.Individual;
import br.unifor.cct.mia.ga.Ga;
import br.unifor.cct.mia.ga.util.FeatureConstructionGene;
import br.unifor.cct.mia.util.Methods;

public class FeatureConstructionXOver extends XOver {

	private void xover(Ga ga, Structure struc) {
        if (ga.configurations.getNvars() > 1) {
            int point = (ga.configurations.getNvars() == 2?1:Methods.randIntValue(1, ga.configurations.getNvars()-1));
            int rest = ga.configurations.getNvars() - point;
            
            FeatureConstructionGene filho[] = new FeatureConstructionGene[ga.configurations.getNvars()];
            
            System.arraycopy(((FeatureConstructionGenotype)ga.population[two]).getGene(), 0, filho, 0, point);
            System.arraycopy(((FeatureConstructionGenotype)ga.population[one]).getGene(), point, filho, point, rest);
                        
            double x = Methods.randDoubleValue(0, 1);

			if (x < ga.configurations.getPmutation()) {				 
				
					int j = Methods.randIntValue(0, ga.configurations.getNvars()-1);

					int type = Methods.randIntValue(0, 1);
					FeatureConstructionGene gen = filho[j];

					if (type == 0) { //Troca apenas o bit                		
						if (gen.getActiveBit() == 0) {
							gen.setActiveBit((byte) 1);
						} else {
							gen.setActiveBit((byte) 0);
						}
					} else { //Troca o valor do atributo
						int pos = -1;
						for (int z = 0; z < struc.size(); z++) {
							Attribute att = struc.getAttribute(z);
							if (att.getName().equalsIgnoreCase(gen.getAttribute())) {
								pos = z;
								break;
							}
						}
						if (pos != -1) {
							List values = struc.getValues(pos);
							int vlPos = Methods.randIntValue(0,values.size() - 1);
							gen.setValue( String.valueOf( values.toArray()[vlPos] ) );
						}
					}
			}
            
			Methods.verificarMinActive( filho );
            replaceWorst(ga,filho);
        }
	}
	
	private void replaceWorst(Ga ga, FeatureConstructionGene[] filho ) {
		Individual[] population = ga.population;
		 
		int minPos = 1;
		double minVal = Integer.MAX_VALUE;
		for ( int i=1; i<ga.configurations.getPopsize(); i++ ) {			
			if ( population[i].fitness>0 && population[i].fitness<minVal ) {
				minPos = i;
				minVal = population[i].fitness;
			}			
		}
		System.arraycopy(filho, 0, ((FeatureConstructionGenotype)population[minPos]).getGene(), 0, filho.length);
		population[minPos].setFitness(-1);
		
	}
	
	public Object execute(Object value) {
    	Object[] o = (Object[])value;
		Ga ga = (Ga)o[0];
		Structure struc = (Structure)o[1];
		
		xover(ga,struc);
		return ga.population;
	}
}